package nachos.vm;

import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import nachos.machine.Machine;
import nachos.machine.OpenFile;
import nachos.machine.Processor;
import nachos.machine.TranslationEntry;

public class VMSwap {
	// free pages
	private LinkedList<Integer> free = new LinkedList<Integer>();
	// used pages
	private ArrayList<Long> used = new ArrayList<Long>();
			
	protected static VMKernel kernel = (VMKernel) VMKernel.kernel;
//	private InvertPageTable pageTable;
	
	private Map<Long,Integer> record = new HashMap<Long,Integer>();
	private OpenFile swapfile;
	
	private static final int pageSize = Processor.pageSize;
	
	public VMSwap(){
		// create file to record creation
		swapfile = Machine.stubFileSystem().open("swap", true);
//        pageTable = kernel.pageTable;
	}
	
	// write out pages to swapfile
	public boolean writeOut(int ppn, int pid, int vpn){
		Integer pos = record.get(((long)pid << 32) | vpn);
		
		if(null == pos){
			if(free.size() > 0){
				pos = free.remove(0);
			}
			else{
				used.add(((long)pid << 32) | vpn);
				pos = used.size() -1 ;
			}
		}
		
		int bytes = swapfile.write(pos * pageSize, Machine.processor().getMemory(), ppn * pageSize, pageSize);
		if(bytes != pageSize)
			return false;
		
		record.put(((long)pid << 32) | vpn, pos);
		used.set(pos, ((long)pid << 32) | vpn);
		return true;
	}
	
	// read pages from file to main memory
	public boolean readIn (int ppn, int pid, int vpn){
		Integer pos = record.get(((long)pid << 32) | vpn);
		if(pos == null){
			return false;
		}
		else{
			int bytes = swapfile.read(pos * pageSize, Machine.processor().getMemory(), ppn * pageSize, pageSize);
			if(bytes != pageSize)
				return false;
		}
		//TranslationEntry t = new TranslationEntry(vpn, ppn, true, false, false, false);
		//pageTable.addEntry(pid, t);
		//pageTable.replacementListIt.add(t);
		return true;
	}
	
	public boolean contains(int pid, int vpn){
		return record.containsKey(((long)pid << 32) | vpn);
	}
	
	public OpenFile getSwapfile(){
		return this.swapfile;
	}
}
